package com.example.auth.service.impl;

import com.example.auth.dto.PageResponse;
import com.example.auth.dto.RoleDTO;
import com.example.auth.dto.UserDTO;
import com.example.auth.entity.Role;
import com.example.auth.entity.User;
import com.example.auth.repository.RoleRepository;
import com.example.auth.repository.UserRepository;
import com.example.auth.service.AdminService;
import com.example.auth.util.PasswordUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import jakarta.annotation.PostConstruct;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@Service
public class AdminServiceImpl implements AdminService {

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private RoleRepository roleRepository;

    private DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    @Override
    public PageResponse<UserDTO> getUserList(int page, int size, String username, String role, String status) {
        Pageable pageable = PageRequest.of(page - 1, size);


        Page<User> users;
        
      
        if ((username != null && !username.isEmpty()) || 
            (role != null && !role.isEmpty()) || 
            (status != null && !status.isEmpty())) {
            
            List<User> filteredUsers = userRepository.findAll();
            
            if (username != null && !username.isEmpty()) {
                filteredUsers = filteredUsers.stream()
                    .filter(user -> user.getUsername().toLowerCase().contains(username.toLowerCase()))
                    .collect(Collectors.toList());
            }
            

            if (role != null && !role.isEmpty()) {
                filteredUsers = filteredUsers.stream()
                    .filter(user -> user.getRoles().stream()
                        .anyMatch(r -> r.getName().equalsIgnoreCase(role)))
                    .collect(Collectors.toList());
            }
            

            if (status != null && !status.isEmpty()) {
                filteredUsers = filteredUsers.stream()
                    .filter(user -> status.equalsIgnoreCase(user.getStatus()))
                    .collect(Collectors.toList());
            }
            

            int start = (int) pageable.getOffset();
            int end = Math.min((start + pageable.getPageSize()), filteredUsers.size());
            
            List<User> pageContent = start < end 
                ? filteredUsers.subList(start, end) 
                : Collections.emptyList();
                
            users = new org.springframework.data.domain.PageImpl<>(
                pageContent, pageable, filteredUsers.size());
        } else {            users = userRepository.findAll(pageable);
        }

        List<UserDTO> userDTOs = users.getContent().stream()
                .map(this::convertToUserDTO)
                .collect(Collectors.toList());

        return new PageResponse<>(userDTOs, users.getTotalElements(), page, size);
    }

    @Override
    @Transactional
    public UserDTO createUser(UserDTO userDTO, String password) {
        User user = new User();
        user.setUsername(userDTO.getUsername());
        // Use PasswordUtils to encrypt the password
        user.setPassword(PasswordUtils.encryptPassword(password));
        user.setRealName(userDTO.getRealName());
        user.setNickname(userDTO.getNickname());
        user.setEmail(userDTO.getEmail());
        user.setPhone(userDTO.getPhone());
        user.setStatus("active"); // Ensure the new user's default status is active
        user.setCreateTime(LocalDateTime.now());

        // Set roles
        List<Role> roles = roleRepository.findByNameIn(userDTO.getRoles());
        user.setRoles(new HashSet<>(roles));

        User savedUser = userRepository.save(user);
        return convertToUserDTO(savedUser);
    }

    @Override
    @Transactional
    public UserDTO updateUser(Long id, UserDTO userDTO) {
        System.out.println("Updating user with ID: " + id + ", new roles: " + userDTO.getRoles());
        Optional<User> optionalUser = userRepository.findById(id);
        if (optionalUser.isPresent()) {
            User user = optionalUser.get();
            user.setRealName(userDTO.getRealName());
            user.setNickname(userDTO.getNickname());
            user.setEmail(userDTO.getEmail());
            user.setPhone(userDTO.getPhone());

            // Update roles - Ensure only one role is set
            if (userDTO.getRoles() != null && !userDTO.getRoles().isEmpty()) {
                // Take only the first role
                String roleName = userDTO.getRoles().get(0);
                System.out.println("Updating user role to: " + roleName);
                List<Role> roles = roleRepository.findByNameIn(Collections.singletonList(roleName));
                if (roles.isEmpty()) {
                    System.out.println("Warning: Role not found: " + roleName);
                } else {
                    System.out.println("Found role: " + roles.get(0).getName() + " (ID: " + roles.get(0).getId() + ")");
                    user.setRoles(new HashSet<>(roles));
                }
            }

            User updatedUser = userRepository.save(user);
            System.out.println("User updated successfully, new roles: " + 
                updatedUser.getRoles().stream().map(role -> role.getName()).collect(Collectors.joining(", ")));
            return convertToUserDTO(updatedUser);
        }
        System.out.println("User not found with ID: " + id);
        return null;
    }

    @Override
    @Transactional
    public void toggleUserStatus(Long id) {
        Optional<User> optionalUser = userRepository.findById(id);
        if (optionalUser.isPresent()) {
            User user = optionalUser.get();
            // Toggle the status
            user.setStatus("active".equals(user.getStatus()) ? "inactive" : "active");
            userRepository.save(user);
        }
    }

    @Override
    @Transactional
    public void resetPassword(Long id, String newPassword) {
        Optional<User> optionalUser = userRepository.findById(id);
        if (optionalUser.isPresent()) {
            User user = optionalUser.get();
            // Use PasswordUtils to encrypt the password
            user.setPassword(PasswordUtils.encryptPassword(newPassword));
            userRepository.save(user);
        }
    }

    @Override
    public List<RoleDTO> getAllRoles() {
        List<Role> roles = roleRepository.findAll();
        return roles.stream()
                .map(this::convertToRoleDTO)
                .collect(Collectors.toList());
    }

    @Override
    @Transactional
    public RoleDTO createRole(RoleDTO roleDTO) {
        Role role = new Role();
        role.setName(roleDTO.getName());
        role.setDescription(roleDTO.getDescription());

        if (roleDTO.getPermissions() != null) {
            role.setPermissions(String.join(",", roleDTO.getPermissions()));
        } else {
            role.setPermissions("");
        }

        role.setCreateTime(LocalDateTime.now());

        Role savedRole = roleRepository.save(role);
        return convertToRoleDTO(savedRole);
    }

    @Override
    @Transactional
    public RoleDTO updateRole(Long id, RoleDTO roleDTO) {
        Optional<Role> optionalRole = roleRepository.findById(id);
        if (optionalRole.isPresent()) {
            Role role = optionalRole.get();
            role.setDescription(roleDTO.getDescription());

            if (roleDTO.getPermissions() != null) {
                role.setPermissions(String.join(",", roleDTO.getPermissions()));
            } else {
                role.setPermissions("");
            }

            Role updatedRole = roleRepository.save(role);
            return convertToRoleDTO(updatedRole);
        }
        return null;
    }

    @Override
    @Transactional
    public void deleteRole(Long id) {
        roleRepository.deleteById(id);
    }

    // Add initialization method to fix data when the service starts
    @PostConstruct
    @Transactional
    public void initializeRoles() {
        List<Role> roles = roleRepository.findAll();
        boolean hasChanges = false;

        for (Role role : roles) {
            if (role.getPermissions() == null) {
                role.setPermissions(""); // Set the default value to an empty string
                hasChanges = true;
            }

            if (role.getCreateTime() == null) {
                role.setCreateTime(LocalDateTime.now()); // Set the current time for empty createTime
                hasChanges = true;
            }
        }

        // Save only when there are changes
        if (hasChanges) {
            roleRepository.saveAll(roles);
        }
    }

    // Helper methods
    private UserDTO convertToUserDTO(User user) {
        UserDTO dto = new UserDTO();
        dto.setId(user.getId());
        dto.setUsername(user.getUsername());
        dto.setRealName(user.getRealName());
        dto.setNickname(user.getNickname());
        dto.setEmail(user.getEmail());
        dto.setPhone(user.getPhone());
        dto.setStatus(user.getStatus());
        if (user.getCreateTime() != null) {
            dto.setCreateTime(user.getCreateTime().format(formatter));
        } else {
            dto.setCreateTime("");
        }

        List<String> roleNames = user.getRoles().stream()
                .map(Role::getName)
                .collect(Collectors.toList());
        dto.setRoles(roleNames);

        return dto;
    }

    private RoleDTO convertToRoleDTO(Role role) {
        RoleDTO dto = new RoleDTO();
        dto.setId(role.getId());
        dto.setName(role.getName());
        dto.setDescription(role.getDescription());

        List<String> permissions;
        if (role.getPermissions() != null) {
            permissions = List.of(role.getPermissions().split(","));
        } else {
            permissions = List.of();
        }
        dto.setPermissions(permissions);

        if (role.getCreateTime() != null) {
            dto.setCreateTime(role.getCreateTime().format(formatter));
        } else {
            dto.setCreateTime(""); // Set a default value to avoid null value issues on the frontend
        }
        return dto;
    }
}